/*
 *    Copyright 2011 The gcal-to-refill project
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */
package com.googlecode.gcal2refill.controller.gcal2refill;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.InvalidPropertiesFormatException;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;

import javax.servlet.http.Cookie;


import org.slim3.controller.Controller;
import org.slim3.controller.Navigation;
import org.slim3.util.StringUtil;

import com.google.gdata.client.authn.oauth.GoogleOAuthHelper;
import com.google.gdata.client.authn.oauth.GoogleOAuthParameters;
import com.google.gdata.client.authn.oauth.OAuthException;
import com.google.gdata.client.authn.oauth.OAuthHmacSha1Signer;
import com.google.gdata.data.calendar.CalendarEntry;
import com.googlecode.gcal2refill.GcalAccessor;
import com.googlecode.gcal2refill.UserInput;

public class IndexController extends Controller {
    private static final Logger logger =
        Logger.getLogger(IndexController.class.getName());

    @Override
    public Navigation run() throws Exception {
        AccessTokenPair accessTokenPair = null;
        String oauthTokenSecret = null;
        String accessToken = null;
        Cookie[] cookies = request.getCookies();
        if (cookies != null){
            for(Cookie cookie : cookies){
                if ("oauth_token_secret".equals(cookie.getName())){
                    oauthTokenSecret = cookie.getValue();
                }else if ("access_token".equals(cookie.getName())){
                    accessToken = cookie.getValue();
                }
            }
            accessTokenPair = new AccessTokenPair(accessToken, oauthTokenSecret);
        }
        if (StringUtil.isEmpty(accessToken)) {
            oauthTokenSecret = asString("oauth_token_secret");
            if (StringUtil.isEmpty(oauthTokenSecret)) {
                return request();
            }else{
                accessTokenPair = getAccessTokenPair(oauthTokenSecret);
            }
        }
        setFormDefault(accessTokenPair.accessToken,accessTokenPair.accessTokenSecret);
        return forward("index.jsp");
    }

    private void setFormDefault(String accessToken,String oauthTokenSecret){
        UserInput ui = new UserInput();
        List<String> calendarList = new ArrayList<String>();
        try{
            Properties props = new Properties();
            GoogleOAuthParameters params = new GoogleOAuthParameters();
            ClassLoader cl = Thread.currentThread().getContextClassLoader();
            props.loadFromXML(cl.getResourceAsStream("gcal2refill_properties.xml"));
            params.setOAuthConsumerKey(props.getProperty("oauth.consumer.key"));
            params.setOAuthConsumerSecret(props.getProperty("oauth.consumer.secret"));
            params.setOAuthSignatureMethod("HMAC-SHA1");
            params.setOAuthTokenSecret(oauthTokenSecret);
            params.setOAuthToken(accessToken);
            GcalAccessor gcalAccess = new GcalAccessor(ui,params);
            List<CalendarEntry> calEntryList = gcalAccess.getCalenderList();
            for (Iterator<CalendarEntry> iterator = calEntryList.iterator(); iterator
                    .hasNext();) {
                CalendarEntry entry = iterator.next();
                calendarList.add(entry.getTitle().getPlainText());
            }
            requestScope("calendarList",calendarList);
        } catch (Exception e) {
            e.printStackTrace();
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar startCal = Calendar.getInstance();
        startCal.set(Calendar.DAY_OF_MONTH, 1);
        if (startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY){
            startCal.add(Calendar.DAY_OF_WEEK, (startCal.get(Calendar.DAY_OF_WEEK) - 2) * -1);
        }else{
            startCal.add(Calendar.DAY_OF_WEEK, -6);
        }
        requestScope("startDate",sdf.format(startCal.getTime()));
        Calendar endCal = Calendar.getInstance();
        endCal.set(Calendar.DAY_OF_MONTH, endCal.getActualMaximum(Calendar.DAY_OF_MONTH));
        endCal.add(Calendar.DAY_OF_WEEK, 7 - endCal.get(Calendar.DAY_OF_WEEK));
        requestScope("weekPeriod",endCal.get(Calendar.WEEK_OF_YEAR) - startCal.get(Calendar.WEEK_OF_YEAR) + 1);
        requestScope("virticalStartTime",ui.getVirticalStartTime());
        requestScope("virticalPeriod",ui.getVirticalPeriod());
        requestScope("sizeOfPaper",ui.getSizeOfPaper());
        requestScope("tojisiroChecked","checked");
        requestScope("tojisiroSize",ui.getTojisiroSize());
    }
    
    private AccessTokenPair getAccessTokenPair(String oauthTokenSecret) {
        AccessTokenPair accessTokenPair = null;
        Properties props = new Properties();
        GoogleOAuthParameters params = new GoogleOAuthParameters();
        try {
            ClassLoader cl = Thread.currentThread().getContextClassLoader();
            props.loadFromXML(cl.getResourceAsStream("gcal2refill_properties.xml"));
            params.setOAuthConsumerKey(props.getProperty("oauth.consumer.key"));
            params.setOAuthConsumerSecret(props.getProperty("oauth.consumer.secret"));
            params.setOAuthSignatureMethod("HMAC-SHA1");
            params.setOAuthTokenSecret(oauthTokenSecret);
            params.setOAuthToken(asString("oauth_token"));
            GoogleOAuthHelper helper = new GoogleOAuthHelper(new OAuthHmacSha1Signer());
            String accessToken = helper.getAccessToken(params);
            Cookie accessTokenCookie = new Cookie("access_token",accessToken);
            accessTokenCookie.setPath("/gcal2refill");
            accessTokenCookie.setMaxAge(60 * 60 * 24 * 14);
            response.addCookie(accessTokenCookie);
            Cookie oauthTokenSecretTokenCookie = new Cookie("oauth_token_secret",params.getOAuthTokenSecret());
            oauthTokenSecretTokenCookie.setPath("/gcal2refill");
            oauthTokenSecretTokenCookie.setMaxAge(60 * 60 * 24 * 14);
            response.addCookie(oauthTokenSecretTokenCookie);
            accessTokenPair = new AccessTokenPair(accessToken,params.getOAuthTokenSecret());
        } catch (InvalidPropertiesFormatException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (OAuthException e) {
            e.printStackTrace();
        }
        return accessTokenPair;
    }
    
    private Navigation request() {
        logger.info("START authRequest.");
        Properties props = new Properties();
        GoogleOAuthParameters params = new GoogleOAuthParameters();
        try {
            ClassLoader cl = Thread.currentThread().getContextClassLoader();
            props.loadFromXML(cl.getResourceAsStream("gcal2refill_properties.xml"));
            params.setOAuthConsumerKey(props.getProperty("oauth.consumer.key"));
            params.setOAuthConsumerSecret(props.getProperty("oauth.consumer.secret"));
            params.setOAuthSignatureMethod("HMAC-SHA1");
            params.setScope("https://www.google.com/calendar/feeds/");
            GoogleOAuthHelper helper = new GoogleOAuthHelper(new OAuthHmacSha1Signer());
            helper.getUnauthorizedRequestToken(params);
        
            String secretToken = "?oauth_token_secret=" + 
                URLEncoder.encode(params.getOAuthTokenSecret(), "UTF-8");
            if ("localhost".equals(request.getServerName())) {
        // ローカル環境
                params.setOAuthCallback("http://localhost:8888/gcal2refill/index" + secretToken);
            } else {
        // 本番環境
                params.setOAuthCallback("http://gcal2refill.appspot.com/gcal2refill/index" + secretToken);
            }
            String requestUrl = helper.createUserAuthorizationUrl(params);
            logger.info("REQUEST URL: " + requestUrl);
            return redirect(requestUrl);
        } catch (OAuthException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (InvalidPropertiesFormatException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return redirect("index.jsp");
    }
    class AccessTokenPair {
        String accessToken;
        String accessTokenSecret;
        AccessTokenPair(String accessToken,String accessTokenSecret){
            this.accessToken = accessToken;
            this.accessTokenSecret = accessTokenSecret;
        }
    }
}
